package com.org.util;


import com.org.dto.SearchRentInstallmentDetailMiniResponseDTO;
import com.org.dto.SearchRentInstallmentDetailRequestDTO;
import com.org.dto.SearchRentInstallmentDetailResponseDTO;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author zhangxurui
 * @Title: 通用方法 - 金融
 * @Description: TODO
 * @date 2018年5月14日 下午8:56:20
 */
public class MyJinRongUtils {

    /**
     * 根据一段时间区间，按月份拆分成多个时间段
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return
     */
    public static List<KeyValueForDate> getSplitMonthForDate(Date start, Date end) {
        String startDate = new SimpleDateFormat("yyyy-MM-dd").format(start);
        String endDate = new SimpleDateFormat("yyyy-MM-dd").format(end);
        List<KeyValueForDate> list = null;
        try {
            list = new ArrayList<KeyValueForDate>();
            Date d1 = new SimpleDateFormat("yyyy-MM-dd").parse(startDate);// 定义起始日期
            Date d2 = new SimpleDateFormat("yyyy-MM-dd").parse(endDate);// 定义结束日期
            Calendar dd = Calendar.getInstance();// 定义日期实例
            dd.setTime(d1);// 设置日期起始时间
            Calendar c = Calendar.getInstance();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            KeyValueForDate keyValueForDate = null;
            while (dd.getTime().before(d2)) {// 判断是否小于结束日期
                if (sdf.format(dd.getTime()).equals(sdf.format(d1))) {
                    keyValueForDate = new KeyValueForDate();
                    keyValueForDate.setStartDate(sdf.format(dd.getTime()));
                    c.setTime(dd.getTime());
                    c.add(Calendar.MONTH, 1);
                    c.add(Calendar.DATE, -1);
                    keyValueForDate.setEndDate(sdf.format(c.getTime()));
                    list.add(keyValueForDate);
                    dd.setTime(c.getTime());
                } else {
                    c.setTime(dd.getTime());
                    c.add(Calendar.DATE, 1);
                    dd.setTime(c.getTime());
                    keyValueForDate = new KeyValueForDate();
                    keyValueForDate.setStartDate(sdf.format(dd.getTime()));
                    c.setTime(dd.getTime());
                    c.add(Calendar.MONTH, 1);
                    SimpleDateFormat mm = new SimpleDateFormat("MM");
                    SimpleDateFormat yy = new SimpleDateFormat("yyyy");
                    int year = Integer.parseInt(yy.format(c.getTime()));
                    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
                        if (mm.format(c.getTime()).equals("02")) {
                        }
                    } else {
                        if (mm.format(c.getTime()).equals("02")) {
                            c.add(Calendar.DATE, 1);
                        }
                    }
                    String checkd1 = sdf.format(c.getTime());
                    String checkd2 = sdf.format(d2.getTime());
                    if (d2.before(c.getTime()) || checkd1.equals(checkd2)) { // 判断是否大于结束日期，是则直接保存结束日期
                        keyValueForDate.setEndDate(sdf.format(d2.getTime()));
                        list.add(keyValueForDate);
                        dd.setTime(c.getTime());
                    } else {// 保存结束日期
                        c.add(Calendar.DATE, -1);
                        keyValueForDate.setEndDate(sdf.format(c.getTime()));
                        list.add(keyValueForDate);
                        dd.setTime(c.getTime());
                    }
                }
            }
        } catch (ParseException e) {
            return null;
        }
        return list;
    }

    /**
     * @param d1
     * @param d2
     * @return double
     * @Description: 进行加法运算
     */
    public static double add(double d1, double d2) { //
        BigDecimal b1 = new BigDecimal(d1);
        BigDecimal b2 = new BigDecimal(d2);
        return b1.add(b2).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * @param d1
     * @param d2
     * @return double
     * @Description: 进行减法运算
     */
    public static double sub(double d1, double d2) {
        BigDecimal b1 = new BigDecimal(d1);
        BigDecimal b2 = new BigDecimal(d2);
        return b1.subtract(b2).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * @param d1
     * @param d2
     * @return double
     * @Description: 进行乘法运算
     */
    public static double mul(double d1, double d2) {
        BigDecimal b1 = new BigDecimal(d1);
        BigDecimal b2 = new BigDecimal(d2);
        return b1.multiply(b2).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * @param d1
     * @param d2
     * @param len
     * @return double
     * @Description: 进行除法运算
     */
    public static double div(double d1, double d2, int len) {
        BigDecimal b1 = new BigDecimal(d1);
        BigDecimal b2 = new BigDecimal(d2);
        return b1.divide(b2, len, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * @param SearchRentInstallmentDetailRequestDTO
     * @return SearchRentInstallmentDetailResponseDTO
     * @throws ParseException
     * @Description: 计算 - 分期利率使用
     */
    public static SearchRentInstallmentDetailResponseDTO getComputeFQ(SearchRentInstallmentDetailRequestDTO dto)
            throws ParseException {
        // 每月租金 = （总金额 / 期数）
        // 每月利息 = 每月租金 * （一次性服务 + 利率）
        // 每月净值 = 每月租金 - 每月利息
        SearchRentInstallmentDetailResponseDTO res = new SearchRentInstallmentDetailResponseDTO();
        List<SearchRentInstallmentDetailMiniResponseDTO> arr = new ArrayList<>();
        SearchRentInstallmentDetailMiniResponseDTO detail;
        double rate = MyJinRongUtils.div(Double.parseDouble(dto.getRate()), 100, 2);// 利率
        double balance = dto.getBalance();// 余额
        double tenantRate = 0;
        double businessRate = 0;
        double serviceFee = 0;
        if (StringUtils.isNotBlank(dto.getTenantRate())) {
            tenantRate = MyJinRongUtils.div(Double.parseDouble(dto.getTenantRate()), 100, 2);// 租客承担比例
        }
        if (StringUtils.isNotBlank(dto.getBusinessRate())) {
            businessRate = MyJinRongUtils.div(Double.parseDouble(dto.getBusinessRate()), 100, 2);// 公寓承担比例
        }
        if (StringUtils.isNotBlank(dto.getServiceFee())) {
            serviceFee = MyJinRongUtils.div(Double.parseDouble(dto.getServiceFee()), 100, 2);// 一次性服务费
        }
        double creditLine = MyJinRongUtils.div(dto.getCreditLine(), 100, 2);// 授信额度 百分比
        List<KeyValueForDate> splitMonth = getSplitMonthForDate(dto.getStartDate(), dto.getEndDate());
        int periods = splitMonth.size(); // 期数
        double monthMonery = div(balance, periods, 2); // 月租金
        double inInterestCount = 0;// 利息合计
        double serviceFeeCount = 0; // 服务费合计
        int no = 1;
        for (KeyValueForDate v : splitMonth) {
            detail = new SearchRentInstallmentDetailMiniResponseDTO();
            detail.setNo(no);
            detail.setRealEstateInfo(dto.getRealEstateInfo());
            detail.setRoomCode(dto.getRoomCode());
            detail.setMonthlyRentReceivable(monthMonery);// 应收
            double rentEndInterest = MyJinRongUtils.getRentEndInterest(balance, tenantRate, creditLine);
            detail.setInstalmentInterest(rentEndInterest);// 分期后利息
            double rentEndMoney = MyJinRongUtils.add(monthMonery, rentEndInterest);
            detail.setMonthlyRentAfStag(rentEndMoney);// 分期后租金
            detail.setStarLoanday(v.getStartDate());
            detail.setEndLoanday(v.getEndDate());
            arr.add(detail);
            no++;
        }

        double reLeaseCount = MyJinRongUtils.mul(balance, creditLine);
        inInterestCount = MyJinRongUtils.getInterests(balance, businessRate, periods, creditLine);// 利息合计
        serviceFeeCount = MyJinRongUtils.getInterests(balance, serviceFee, periods, creditLine); // 服务费合计
        res.setReLeaseCount(reLeaseCount + "");// 应收租约合计（授信后）
        res.setInInterestCount(inInterestCount + "");// 公寓利息合计
        res.setSerCharge(serviceFeeCount + "");// 服务费合计
        res.setCoHirerentCount(MyJinRongUtils.getCoHirerent(reLeaseCount, inInterestCount, serviceFeeCount) + "");// 分期后租金合计
        res.setRentInstalDetail(arr);
        return res;
    }

    /**
     * @param monthMonery
     * @param inInterestCount
     * @param serviceFeeCount
     * @return double 服务费总 = 总额 * (服务费、公寓、利率等) / 12 * 期数
     * @Description: 计算 - 利息
     */
    public static double getInterests(double balance, double interest, int periods, double creditLine) {
        double mul = MyJinRongUtils.mul(balance, interest);
        double div = MyJinRongUtils.div(mul, 12, 2);
        double mul2 = MyJinRongUtils.mul(div, periods);
        return MyJinRongUtils.mul(mul2, creditLine);
    }

    /**
     * @param monthMonery
     * @param inInterestCount
     * @param serviceFeeCount
     * @return double
     * @Description: 计算 - 分期后租金合计
     */
    public static double getCoHirerent(double balance, double inInterestCount, double serviceFeeCount) {
        double sub = MyJinRongUtils.sub(balance, inInterestCount);
        return MyJinRongUtils.sub(sub, serviceFeeCount);
    }

    /**
     * @param monthMonery
     * @param businessRate
     * @param creditLine
     * @return double
     * @Description: 计算 - 利息
     */
    public static double getRentEndInterest(double monthMonery, double tenantRate, double creditLine) {
        double mul = MyJinRongUtils.mul(monthMonery, tenantRate);
        double mul2 = MyJinRongUtils.mul(mul, creditLine);
        return MyJinRongUtils.div(mul2, 12, 2);
    }

    /**
     * @param reLeaseCount 应收租约合计（授信后）
     * @param rate         利息
     * @return double
     * @Description: 计算 - 利息总和 - 审核使用
     */
    public static double getInterestCount(double reLeaseCount, double rate) {
        double mul = MyJinRongUtils.mul(reLeaseCount, rate);
        double div = MyJinRongUtils.div(mul, 12, 2);
        return MyJinRongUtils.div(div, 100, 2);
    }

    public static class KeyValueForDate {
        private String startDate;
        private String endDate;

        public String getStartDate() {
            return startDate;
        }

        public void setStartDate(String startDate) {
            this.startDate = startDate;
        }

        public String getEndDate() {
            return endDate;
        }

        public void setEndDate(String endDate) {
            this.endDate = endDate;
        }
    }

}
